package com.pwser.filter;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import com.pwser.constant.ConstantKey;
import com.pwser.exception.TokenException;

import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;

/**
 * 自定义JWT认证过滤器 该类继承自BasicAuthenticationFilter，在doFilterInternal方法中，
 * 从http头的Authorization 项读取token数据，然后用Jwts包提供的方法校验token的合法性。
 * 如果校验通过，就认为这是一个取得授权的合法请求
 * 
 */
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

	private static final Logger logger = LoggerFactory.getLogger(JWTAuthenticationFilter.class);

	public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
		super(authenticationManager);
	}

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		
		Cookie[] cookies = request.getCookies();
		if(cookies == null ) {
			chain.doFilter(request, response);
			return;
		}
		
		String token = null;
		Cookie tokenCookie = null;
		for (Cookie cookie : cookies) {
			switch (cookie.getName()) {
			case "Authorization":
				tokenCookie = cookie;
				if(request.getParameter("logout") != null) { //注销时删除cookie
					delCookie(tokenCookie, response);
					response.sendRedirect(request.getContextPath() + "/login");
					return;
				}
				token = cookie.getValue();
				break;
			default:
				break;
			}
		}
		if (token == null || !token.startsWith("token:")) {
			chain.doFilter(request, response);
			return;
		}
		try {
			UsernamePasswordAuthenticationToken authentication = getAuthentication(token);
			SecurityContextHolder.getContext().setAuthentication(authentication);
			chain.doFilter(request, response);
		} catch (Exception e) {
			delCookie(tokenCookie, response);
			request.getSession().setAttribute("msg", e.getMessage());
			response.sendRedirect(request.getContextPath() + "/login?error=true");
			return;
		}
	}

	private UsernamePasswordAuthenticationToken getAuthentication(String token) {
		long start = System.currentTimeMillis();
		if (token == null || token.isEmpty()) {
			throw new TokenException("Token为空");
		}
		// parse the token.
		String user = null;
		try {
			user = Jwts.parser().setSigningKey(ConstantKey.SIGNING_KEY).parseClaimsJws(token.replace("token:", ""))
					.getBody().getSubject();
			long end = System.currentTimeMillis();
//			logger.info("执行时间: {}", (end - start) + " 毫秒");
			if (user != null) {
				String[] split = user.split("-")[1].replace("[", "").replace("]", "").split(",");
//				System.out.println(split[0]);
				ArrayList<GrantedAuthority> authorities = new ArrayList<>();
				for (int i = 0; i < split.length; i++) {
					authorities.add(new SimpleGrantedAuthority(split[i]));
				}
				return new UsernamePasswordAuthenticationToken(user.split("-")[0], null, authorities);
			}

		} catch (ExpiredJwtException e) {
			logger.error("Token已过期: {} " + e);
			throw new TokenException("Token已过期");
		} catch (UnsupportedJwtException e) {
			logger.error("Token格式错误: {} " + e);
			throw new TokenException("Token格式错误");
		} catch (MalformedJwtException e) {
			logger.error("Token没有被正确构造: {} " + e);
			throw new TokenException("Token没有被正确构造");
		} catch (SignatureException e) {
			logger.error("签名失败: {} " + e);
			throw new TokenException("签名失败");
		} catch (IllegalArgumentException e) {
			logger.error("非法参数异常: {} " + e);
			throw new TokenException("非法参数异常");
		}

		return null;
	}
	
	public void delCookie(Cookie cookie, HttpServletResponse response) {
		cookie.setMaxAge(0);
		response.addCookie(cookie);
	}

}
